package com.asyf.demo.config.mydefined;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author yjz
 * @Date 2023/1/1 10:24
 */
public class MyConnectionLeakProxy {
    private static final Map<Connection, Throwable> stacks = new ConcurrentHashMap();
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final Map<Connection, ConnectionLeakInfo> stacks2 = new ConcurrentHashMap();


    public MyConnectionLeakProxy() {
    }

    public static Connection newProxy(Connection conn, String poolName) {
        String now = formatter.format(LocalDateTime.now());
        //可以给这个Exception封装到一个类，记录一下连接开始使用时间，这样就能根据时间差获取真正泄露的连接
        Exception e = new Exception("[" + now + "] 检测连接[" + poolName + "]");
        stacks.put(conn, e);
        ConnectionLeakInfo connectionLeakInfo = new ConnectionLeakInfo();
        connectionLeakInfo.setStartTime(new Date());
        connectionLeakInfo.setT(e);
        stacks2.put(conn, connectionLeakInfo);
        Connection result = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object var5;
                try {
                    Object result = method.invoke(conn, args);
                    var5 = result;
                } finally {
                    if (method.getName().equals("close")) {
                        MyConnectionLeakProxy.stacks.remove(conn);
                        MyConnectionLeakProxy.stacks2.remove(conn);
                    }

                }

                return var5;
            }
        });
        return result;
    }

    public static Throwable getStackTrace(Connection conn) {
        return (Throwable) stacks.get(conn);
    }

    public static Map<Connection, Throwable> getLeakConnections() {
        return Collections.unmodifiableMap(stacks);
    }

    public static Map<Connection, ConnectionLeakInfo> getLeakConnections2() {
        return Collections.unmodifiableMap(stacks2);
    }
}
